﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Threading;
using System.Xml.Serialization;
using LibrarySync2.Common.Event;
using LibrarySync2.Common.Enum;
using LibrarySync2.Common.Extensions;
using LibrarySync2.Common.Xml;
using System.Xml;


namespace LibrarySync2.Business.FileSystem.Item
{
    [Serializable]
    public class File : FileSystemItem<FileInfo>
    {
        //Max quick copy size == 10MB
        public const int QuickFileCopyMaxFileSize = 10485760;
        //Slow copy buffer == 10MB
        public int CopyBufferSize = 10485760;

        public long FileSize { get; set; }
        public DateTime CreatedDate { get; set; }

        public string RelativeDirectoryPath
        {
            get { return RelativePath.Substring(0, RelativePath.Length - Name.Length); }
        }

        public File()
            : base()
        {
            //Do nothing.  Deserializing.
        }

        internal File(FileInfo fileInfo, string root) 
            : base(fileInfo, root)
        {
            FileSize = fileInfo.Length;
            CreatedDate = fileInfo.CreationTime;
        }

        protected override List<FileSystemInfo> GetChildren()
        {
            return new List<FileSystemInfo>();
        }

        protected void PerformCopy(string fullDestinationPath, FileInfo toCopy, BackgroundWorker copyWorker, EventHandler<CopyEventArgs> copyEvent)
        {
            if (toCopy.Length <= QuickFileCopyMaxFileSize)
            {
                copyEvent.Raise(this, new CopyEventArgs(CopyStatusType.Starting, string.Format("Copying {0}...", toCopy.FullName)));
                toCopy.CopyTo(fullDestinationPath, true);
                return;
            }

            byte[] buffer = new byte[CopyBufferSize];
            int bytesRead;
            long totalBytesProcessed = 0L;
            long fileLength = toCopy.Length;

            var destinationFile = new FileInfo(fullDestinationPath);

            int copies = 0;

            copyEvent.Raise(this, new CopyEventArgs(CopyStatusType.Starting, string.Format("Begin Copying {0}...", toCopy.FullName)));

            using (BinaryReader reader = new BinaryReader(toCopy.OpenRead()))
            using (BinaryWriter writer = new BinaryWriter(destinationFile.OpenWrite()))
            {
                while (true)
                {
                    if (copyWorker.CancellationPending)
                        break;

                    bytesRead = reader.Read(buffer, 0, CopyBufferSize);
                    if (bytesRead == 0)
                        break;

                    writer.Write(buffer, 0, bytesRead);
                    if (bytesRead < CopyBufferSize)
                        break;

                    writer.Flush();

                    totalBytesProcessed += bytesRead;

                    if (copies++ % 20 == 0)
                        copyEvent.Raise(this, new CopyEventArgs(CopyStatusType.CopyFileProgress,
                            string.Format("Copying {0}: {1} of {2} bytes copied", toCopy.FullName, totalBytesProcessed, fileLength)));

                    Thread.Sleep(5);
                }
                writer.Flush();
                copyEvent.Raise(this, new CopyEventArgs(CopyStatusType.CopyFileProgress,
                        string.Format("Copying {0}: Copy {1}.", toCopy.FullName, copyWorker.CancellationPending ? "cancelled" : "complete")));
            }

            if (copyWorker.CancellationPending)
                destinationFile.Delete();

            //Not sure how variable we want to keep this.
            Thread.Sleep(50);
        }

        protected override void WriteElementsToXml(XmlWriter writer)
        {
            base.WriteElementsToXml(writer);
            writer.WriteElementString("FileSize", FileSize.ToString());
            writer.WriteElementString("CreatedDate", CreatedDate.ToString("MM/dd/yyyy hh:mm:ss"));
        }

        protected override void ReadElementsFromXml(XmlNode itemNode)
        {
            base.ReadElementsFromXml(itemNode);
            FileSize = itemNode.GetNodeValueAs<long>("FileSize", XmlExtensionMethods.ParseLong).Value;
            CreatedDate = itemNode.GetNodeValueAs<DateTime>("CreatedDate", XmlExtensionMethods.ParseDateTime).Value;
        }
    }
}
